﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Markup;
using TweetSharp.Twitter.Model;
using System.Windows.Input;

namespace Halfwit.Converters
{
    public class TwitterTextConverter : MarkupExtension, IValueConverter
    {
        const string httpMarker = "http://";

        private static Binding _urlBinding = new Binding { ElementName = "me", Path = new PropertyPath("DataContext.NavigateToUrl") };
        private static Binding _searchBinding = new Binding { ElementName = "me", Path = new PropertyPath("DataContext.NavigateToSearch") };
        private static Binding _userBinding = new Binding { ElementName = "me", Path = new PropertyPath("DataContext.NavigateToUser") };

        private static ContextMenu _urlMenu = new ContextMenu
        {
            Items = 
            {
                new MenuItem
                {
                    Header = "_Copy Shortcut",
                    Command = new RelayCommand("_Copy", o => 
                        {
                            try 
	                        {	        
                                Clipboard.SetText(o.ToString());
                        	}
	                        catch
                            {
	                        }
                        }
                    ),        
                }
            }
        };

        private static Hyperlink CreateUriLink(string uri)
        {
            var link = new Hyperlink();

            link.TextDecorations = null;
            link.Inlines.Add(uri);
            link.SetBinding(Hyperlink.CommandProperty, _urlBinding);
            link.CommandParameter = uri;

            link.ContextMenu = _urlMenu;
            // not using ContextMenu because we don't want a right-click to select the tweet
            link.PreviewMouseRightButtonDown += (o, e) =>
                {
                    e.Handled = true;
                    
                    var l = o as Hyperlink;
                    ((MenuItem)_urlMenu.Items[0]).CommandParameter = l.CommandParameter;
                    //_urlMenu.PlacementTarget = l.Parent as UIElement;
                    //_urlMenu.IsOpen = true;
                };
            return link;
        }

        private static Hyperlink CreateSearchLink(string phrase)
        {
            var link = new Hyperlink();

            link.TextDecorations = null;
            link.Inlines.Add(phrase);
            link.SetBinding(Hyperlink.CommandProperty, _searchBinding);
            link.CommandParameter = phrase;
            link.ToolTip = "Find tweets containing " + phrase;
            return link;
        }

        private static Hyperlink CreateUserLink(string user)
        {
            var userSansAtPrefix = user.Substring(1);

            var link = new Hyperlink();

            link.TextDecorations = null;
            link.Inlines.Add(user);
            link.SetBinding(Hyperlink.CommandProperty, _userBinding);
            link.CommandParameter = userSansAtPrefix;
            link.ToolTip = "View tweets by " + userSansAtPrefix;
            return link;
        }

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var tweet = value as TwitterStatus;
            if (tweet == null) return null;

            var text = tweet.RetweetedStatus == null ? tweet.Text : tweet.RetweetedStatus.Text;
            if (text == null) return null;

            text = System.Web.HttpUtility.HtmlDecode(text);
            var textBlock = new TextBlock
            {
                TextWrapping = System.Windows.TextWrapping.Wrap,
            };

            // some very basic text parsing for usernames
            int c = 0;
            while (c < text.Length)
            {
                if (text[c] == '@') // mention
                {
                    int i = c + 1;
                    while (i < text.Length && (char.IsLetterOrDigit(text[i]) || text[i] == '_')) i++;

                    if (i > c + 1)
                    {
                        var link = CreateUserLink(text.Substring(c, i - c));
                        textBlock.Inlines.Add(link);

                        c = i;
                        continue;
                    }

                }
                else if (text[c] == '#') // hashtag
                {
                    int i = c + 1;
                    while (i < text.Length && (char.IsLetterOrDigit(text[i]) || text[i] == '_')) i++;

                    if (i > c + 1)
                    {
                        var link = CreateSearchLink(text.Substring(c, i - c));
                        textBlock.Inlines.Add(link);

                        c = i;
                        continue;
                    }
                }
                else if (text.Length - c > httpMarker.Length && text.Substring(c, 7) == httpMarker)
                {
                    var i = c;

                    string url = text.Substring(i, 7);
                    i += 7;
                    while (i < text.Length && !char.IsWhiteSpace(text[i]))
                    {
                        url += text[i++];
                    }

                    if (i > c + 7)
                    {
                        var link = CreateUriLink(text.Substring(c, i - c));
                        textBlock.Inlines.Add(link);

                        c = i;
                        continue;
                    }
                }

                // look for the next special thing (@mention, #hashtag, URI)
                var nextStop = text.IndexOfAny(new[] { '@', '#', }, c + 1);
                var nextHttp = text.IndexOf(httpMarker, c + 1);

                if (nextHttp > 0 && (nextStop < 0 || nextHttp < nextStop))
                {
                    nextStop = nextHttp;
                }

                if (nextStop >= c)
                {
                    // add plain text up to the next special thing
                    textBlock.Inlines.Add(text.Substring(c, nextStop - c));
                    c = nextStop;
                }
                else
                {
                    // no more special things to look for, so we're done
                    textBlock.Inlines.Add(text.Substring(c));
                    break;
                }
            }
            return textBlock;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }
}
